Imports Clo = Enhancements.Core.Logging
Imports Cmp = System.Runtime.CompilerServices
Imports Gen = System.Collections.Generic
Imports Glo = System.Globalization
Imports Iou = System.IO
Imports Ref = System.Reflection
Imports Reg = System.Text.RegularExpressions
Imports Sys = System
Imports Tex = System.Text
Imports Xsd = System.Xml.Schema
Imports W3c = System.Xml

Namespace Enhancements.Basic.Primitives
    ''' <summary>Contains features that add up to the .Net Framework System.String primitive type.</summary>
    <Serializable(), DebuggerStepThrough()> _
    Public Module [String]

        ''' <summary>Returns the parts obtained by splitting a value using a supplied separator.</summary>
        ''' <param name="_value">Value to split.</param>
        ''' <param name="_separator">Separator to use.</param>
        ''' <exception cref="IsNullException">_value is null, or _separator is null.</exception>
        ''' <exception cref="IsEmptyException">_separator is empty.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function Split(ByVal _value As System.String, ByVal _separator As System.String) As String()
            _value.IsNullNot("_value", True)
            _separator.IsEmptyNot("_separator", True)

            Dim _returnValueList As Gen.List(Of System.String) = New Gen.List(Of System.String)
            Dim _valueCloned As System.String = New Tex.StringBuilder(_value).ToString()
            If _valueCloned <> String.Empty Then
                Do While True
                    Dim _separatorIndex As Sys.Int32 = _valueCloned.IndexOf(_separator)
                    If _separatorIndex <> -1 Then
                        _returnValueList.Add(_valueCloned.Substring(0, _separatorIndex))
                        _valueCloned = _valueCloned.Remove(0, _separatorIndex + 1)
                    Else
                        _returnValueList.Add(_valueCloned)
                        Exit Do
                    End If
                Loop
            End If

            Return _returnValueList.ToArray()
        End Function

        ''' <summary>Returns the parts obtained by splitting a value using a supplied separator.</summary>
        ''' <param name="_value">Value to split.</param>
        ''' <param name="_separator">Separator to use.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function Split(ByVal _value As System.String, ByVal _separator As System.Char) As String()
            Dim _returnValue() As System.String = _value.Split(CType(_separator, System.String))

            Return _returnValue
        End Function

        ''' <summary>Determines the occurrences of a value in another value.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search in the base value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToSearch is null.</exception>
        ''' <exception cref="IsEmptyException">_valueToSearch is empty.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function FindOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.String) As Occurrence()
            _value.IsNullNot("_value", True)
            _valueToSearch.IsEmptyNot("_valueToSearch", True)

            Dim _returnValueList As Gen.List(Of Occurrence) = New Gen.List(Of Occurrence)
            Dim _valueToSearchIndex As Sys.Int32 = 0
            Do While True
                Dim _valueToSearchOccurrenceFoundBeginIndex As Sys.Int32 = _value.IndexOf(_valueToSearch, _valueToSearchIndex)
                If _valueToSearchOccurrenceFoundBeginIndex = -1 Then
                    Exit Do
                Else
                    _returnValueList.Add(New Occurrence(_valueToSearchOccurrenceFoundBeginIndex, _valueToSearchOccurrenceFoundBeginIndex + _valueToSearch.Length - 1))
                    _valueToSearchIndex = _valueToSearchOccurrenceFoundBeginIndex + _valueToSearch.Length
                    If _valueToSearchIndex >= _value.Length Then
                        Exit Do
                    End If
                End If
            Loop

            Return _returnValueList.ToArray()
        End Function

        ''' <summary>Determines the occurrences of a value in another value.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search in the base value.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function FindOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.Char) As Occurrence()
            Dim _returnValue() As Occurrence = _value.FindOccurrences(CType(_valueToSearch, System.String))

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the removal of the occurrences of a string in another one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToRemove">Value to search and remove from the base value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToRemove is null.</exception>
        ''' <exception cref="IsEmptyException">_valueToRemove is empty.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function RemoveOccurrences(ByVal _value As System.String, ByVal _valueToRemove As System.String) As System.String
            _value.IsNullNot("_value", True)
            _valueToRemove.IsEmptyNot("_valueToRemove", True)

            Dim _returnValueStringBuilder As Tex.StringBuilder = New Tex.StringBuilder(_value)
            Dim _occurrences() As Occurrence = _value.FindOccurrences(_valueToRemove)
            For _counter As Integer = _occurrences.Length - 1 To 0 Step -1
                _returnValueStringBuilder.Remove(_occurrences(_counter).BeginIndex, _occurrences(_counter).EndIndex - _occurrences(_counter).BeginIndex + 1)
            Next _counter

            Return _returnValueStringBuilder.ToString()
        End Function

        ''' <summary>Returns a string that is the result of the removal of the occurrences of a string in another one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToRemove">Value to search and remove from the base value.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function RemoveOccurrences(ByVal _value As System.String, ByVal _valueToRemove As System.Char) As System.String
            Dim _returnValue As System.String = _value.RemoveOccurrences(CType(_valueToRemove, System.String))

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the replacement of the occurrences of a string in another string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search and replace from the base value.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToSearch is null, or _valueToReplace is null.</exception>
        ''' <exception cref="IsEmptyException">_valueToSearch is empty.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function ReplaceOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.String, ByVal _valueToReplace As System.String) As System.String
            _value.IsNullNot("_value", True)
            _valueToSearch.IsEmptyNot("_valueToSearch", True)
            _valueToReplace.IsNullNot("_valueToReplace", True)

            Dim _returnValueStringBuilder As Tex.StringBuilder = New Tex.StringBuilder(_value)
            Dim _occurrences() As Occurrence = _value.FindOccurrences(_valueToSearch)
            For _counter As Integer = _occurrences.Length - 1 To 0 Step -1
                _returnValueStringBuilder.Remove(_occurrences(_counter).BeginIndex, _occurrences(_counter).EndIndex - _occurrences(_counter).BeginIndex + 1)
                _returnValueStringBuilder.Insert(_occurrences(_counter).BeginIndex, _valueToReplace)
            Next _counter

            Return _returnValueStringBuilder.ToString()
        End Function

        ''' <summary>Returns a string that is the result of the replacement of the occurrences of a string in another string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search and replace from the base value.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToSearch is null.</exception>
        ''' <exception cref="IsEmptyException">_valueToSearch is empty.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function ReplaceOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.String, ByVal _valueToReplace As System.Char) As System.String
            Dim _returnValue As System.String = _value.ReplaceOccurrences(_valueToSearch, CType(_valueToReplace, System.String))

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the replacement of the occurrences of a string in another string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search and replace from the base value.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToReplace is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function ReplaceOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.Char, ByVal _valueToReplace As System.String) As System.String
            Dim _returnValue As System.String = _value.ReplaceOccurrences(CType(_valueToSearch, System.String), _valueToReplace)

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the replacement of the occurrences of a string in another string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_valueToSearch">Value to search and replace from the base value.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function ReplaceOccurrences(ByVal _value As System.String, ByVal _valueToSearch As System.Char, ByVal _valueToReplace As System.Char) As System.String
            Dim _returnValue As System.String = _value.ReplaceOccurrences(CType(_valueToSearch, System.String), CType(_valueToReplace, System.String))

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the replacement of an interval of a string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_beginIndex">Index of the interval beginning.</param>
        ''' <param name="_endIndex">Index of the interval ending.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null, or _valueToReplace is null.</exception>
        ''' <exception cref="IsEmptyException">_value is empty.</exception>
        ''' <exception cref="IsInRangeNotException">_beginIndex is lower than 0 or higher than _value.Length-1, or _endIndex is lower than _beginIndex or higher than _value.Length-1.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function Replace(ByVal _value As System.String, ByVal _beginIndex As Sys.Int32, ByVal _endIndex As Sys.Int32, ByVal _valueToReplace As System.String) As System.String
            _value.IsEmptyNot("_value", True)
            _beginIndex.IsInRange("_beginIndex", 0, _value.Length - 1, True)
            _endIndex.IsInRange("_endIndex", _beginIndex, _value.Length - 1, True)
            _valueToReplace.IsNullNot("_valueToReplace", True)

            Dim _returnValueStringBuilder As Tex.StringBuilder = New Tex.StringBuilder(_value)
            _returnValueStringBuilder.Remove(_beginIndex, _endIndex - _beginIndex + 1)
            _returnValueStringBuilder.Insert(_beginIndex, _valueToReplace)

            Return _returnValueStringBuilder.ToString()
        End Function

        ''' <summary>Returns a string that is the result of the replacement of an interval of a string, with a replacement one.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <param name="_beginIndex">Index of the interval beginning.</param>
        ''' <param name="_endIndex">Index of the interval ending.</param>
        ''' <param name="_valueToReplace">Replacement value.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <exception cref="IsEmptyException">_value is empty.</exception>
        ''' <exception cref="IsInRangeNotException">_beginIndex is lower than 0 or higher than _value.Length-1, or _endIndex is lower than _beginIndex or higher than _value.Length-1.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function Replace(ByVal _value As System.String, ByVal _beginIndex As Sys.Int32, ByVal _endIndex As Sys.Int32, ByVal _valueToReplace As System.Char) As System.String
            Dim _returnValue As System.String = _value.Replace(_beginIndex, _endIndex, CType(_valueToReplace, System.String))

            Return _returnValue
        End Function

        ''' <summary>Returns the groups found in a string that live in between a group prefix and a group suffix.</summary>
        ''' <param name="_value">Value to examine.</param>
        ''' <param name="_groupPrefix">Prefix to look for.</param>
        ''' <param name="_groupSuffix">Suffix to look for.</param>
        ''' <param name="_includeGroupPrefixAndSuffix">Whether the resulting values must include the group prefix and suffix.</param>
        ''' <exception cref="IsNullException">_value is null, or _groupPrefix is null, or _groupSuffix is null.</exception>
        ''' <exception cref="IsEmptyException">_groupPrefix is empty, or _groupSuffix is empty.</exception>
        ''' <exception cref="StringInvalidException">_value contains incomplete groups, or _value contains values in between groups.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function SplitGroups(ByVal _value As System.String, ByVal _groupPrefix As System.String, ByVal _groupSuffix As System.String, ByVal _includeGroupPrefixAndSuffix As System.Boolean) As String()
            _value.IsNullNot("_value", True)
            _groupPrefix.IsEmptyNot("_groupPrefix", True)
            _groupSuffix.IsEmptyNot("_groupSuffix", True)

            Dim _returnValueList As Gen.List(Of System.String) = New Gen.List(Of System.String)()
            Dim _valueCloned As System.String = New Tex.StringBuilder(_value).ToString()
            Do While _valueCloned.Length >= 1
                If Not _valueCloned.StartsWith(_groupPrefix, StringComparison.OrdinalIgnoreCase) Then
                    StringInvalidException.___Throw("_value", _value)
                Else
                    _valueCloned = _valueCloned.Remove(0, _groupPrefix.Length)
                    Dim _separatorSuffixIndex As Sys.Int32 = _valueCloned.IndexOf(_groupSuffix)
                    If _separatorSuffixIndex = -1 Then
                        StringInvalidException.___Throw("_value", _value)
                    Else
                        If _includeGroupPrefixAndSuffix Then
                            _returnValueList.Add(_groupPrefix + _valueCloned.Substring(0, _separatorSuffixIndex) + _groupSuffix)
                        Else
                            _returnValueList.Add(_valueCloned.Substring(0, _separatorSuffixIndex))
                        End If
                        _valueCloned = _valueCloned.Remove(0, _separatorSuffixIndex + _groupSuffix.Length)
                    End If
                End If
            Loop

            Return _returnValueList.ToArray()
        End Function

        ''' <summary>Returns the groups found in a string that live in between a group prefix and a group suffix.</summary>
        ''' <param name="_value">Value to examine.</param>
        ''' <param name="_groupPrefix">Prefix to look for.</param>
        ''' <param name="_groupSuffix">Suffix to look for.</param>
        ''' <param name="_includeGroupPrefixAndSuffix">Whether the resulting values must include the group prefix and suffix.</param>
        ''' <exception cref="IsNullException">_value is null, or _groupPrefix is null.</exception>
        ''' <exception cref="IsEmptyException">_groupPrefix is empty.</exception>
        ''' <exception cref="StringInvalidException">_value contains incomplete groups, or _value contains values in between groups.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function SplitGroups(ByVal _value As System.String, ByVal _groupPrefix As System.String, ByVal _groupSuffix As System.Char, ByVal _includeGroupPrefixAndSuffix As System.Boolean) As String()
            _value.IsNullNot("_value", True)
            _groupPrefix.IsEmptyNot("_groupPrefix", True)

            Dim _returnValue() As System.String = _value.SplitGroups(_groupPrefix, CType(_groupSuffix, System.String), _includeGroupPrefixAndSuffix)

            Return _returnValue
        End Function

        ''' <summary>Returns the groups found in a string that live in between a group prefix and a group suffix.</summary>
        ''' <param name="_value">Value to examine.</param>
        ''' <param name="_groupPrefix">Prefix to look for.</param>
        ''' <param name="_groupSuffix">Suffix to look for.</param>
        ''' <param name="_includeGroupPrefixAndSuffix">Whether the resulting values must include the group prefix and suffix.</param>
        ''' <exception cref="IsNullException">_value is null, or _groupSuffix is null.</exception>
        ''' <exception cref="IsEmptyException">_groupSuffix is empty.</exception>
        ''' <exception cref="StringInvalidException">_value contains incomplete groups, or _value contains values in between groups.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function SplitGroups(ByVal _value As System.String, ByVal _groupPrefix As System.Char, ByVal _groupSuffix As System.String, ByVal _includeGroupPrefixAndSuffix As System.Boolean) As String()
            _value.IsNullNot("_value", True)
            _groupSuffix.IsEmptyNot("_groupSuffix", True)

            Dim _returnValue() As System.String = _value.SplitGroups(CType(_groupPrefix, System.String), _groupSuffix, _includeGroupPrefixAndSuffix)

            Return _returnValue
        End Function

        ''' <summary>Returns the groups found in a string that live in between a group prefix and a group suffix.</summary>
        ''' <param name="_value">Value to examine.</param>
        ''' <param name="_groupPrefix">Prefix to look for.</param>
        ''' <param name="_groupSuffix">Suffix to look for.</param>
        ''' <param name="_includeGroupPrefixAndSuffix">Whether the resulting values must include the group prefix and suffix.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <exception cref="StringInvalidException">_value contains incomplete groups, or _value contains values in between groups.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function SplitGroups(ByVal _value As System.String, ByVal _groupPrefix As System.Char, ByVal _groupSuffix As System.Char, ByVal _includeGroupPrefixAndSuffix As System.Boolean) As String()
            _value.IsNullNot("_value", True)

            Dim _returnValue() As System.String = _value.SplitGroups(CType(_groupPrefix, System.String), CType(_groupSuffix, System.String), _includeGroupPrefixAndSuffix)

            Return _returnValue
        End Function

        ''' <summary>Returns a string that is the result of the removal of all occurrences of Unicode whitespace.</summary>
        ''' <param name="_value">Base value.</param>
        ''' <exception cref="IsNullException">_value is null.</exception>
        ''' <returns> </returns>
        <Cmp.Extension()> _
        Public Function RemoveUnicodeWhiteSpace(ByVal _value As System.String) As System.String
            _value.IsNullNot("_value", True)

            Dim _returnValueStringBuilder As Tex.StringBuilder = New Tex.StringBuilder(_value)
            Do While _returnValueStringBuilder.Length > 0
                If _returnValueStringBuilder.Chars(0).IsUnicodeWhiteSpace("_returnValueStringBuilder.Chars(0)", False) Then
                    _returnValueStringBuilder.Remove(0, 1)
                Else
                    Exit Do
                End If
            Loop
            For _counter As Sys.Int32 = _returnValueStringBuilder.Length - 1 To 0 Step -1
                If _returnValueStringBuilder.Chars(_counter).IsUnicodeWhiteSpace("_returnValueStringBuilder.Chars(_counter)", False) Then
                    _returnValueStringBuilder.Remove(_counter, 1)
                Else
                    Exit For
                End If
            Next _counter

            Return _returnValueStringBuilder.ToString()
        End Function

    End Module
End Namespace
